//
//  Created by Jesse Squires
//  http://www.jessesquires.com
//
//
//  Documentation
//  http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
//  GitHub
//  https://github.com/jessesquires/JSQMessagesViewController
//
//
//  License
//  Copyright (c) 2014 Jesse Squires
//  Released under an MIT license: http://opensource.org/licenses/MIT
//

#import "JSQMessage.h"


@interface JSQMessage ()


@property (nonatomic, assign) BOOL mediaMessage;


- (instancetype)initWithMessageModel:(JSQMessageModel *)messageModel withMessageMediaData:(id<JSQMessageMediaData>)messageMediaData;

@end



@implementation JSQMessage

- (instancetype)initWithMessageModel:(JSQMessageModel *)messageModel withMessageMediaData:(id<JSQMessageMediaData>)messageMediaData {
    NSParameterAssert(messageModel != nil);

    self = [super init];
    if (self) {
        self.messageModel = messageModel;
        if (messageMediaData) {
            self.mediaData = messageMediaData;
            self.mediaMessage = YES;
        } else {
            self.mediaMessage = NO;
            self.mediaData = nil;
        }
    }
    return self;
}

#pragma mark - Initialization

+ (instancetype)messageWithModel:(JSQMessageModel *)messageModel withMessageMediaData:(id<JSQMessageMediaData>)messageMediaData {
    return [[self alloc] initWithMessageModel:messageModel withMessageMediaData:messageMediaData];
}

- (id)init {
    NSAssert(NO, @"%s is not a valid initializer for %@.", __PRETTY_FUNCTION__, [self class]);
    return nil;
}

- (void)dealloc {
    _messageModel = nil;
}

- (NSAttributedString *)attributedText {
    return self.messageModel.attributedText;
}

- (NSString *)sessionID {
    return self.messageModel.sessionID;
}

- (NSString *)messageID {
    return self.messageModel.messageID;
}

- (NSString *)mimeType {
    return self.messageModel.mimeType;
}

- (NSInteger)messageType {
    return self.messageModel.messageType;
}

- (NSInteger)messageStatus {
    return self.messageModel.messageStatus;
}

- (NSUInteger)messageHash {
    return self.hash;
}

- (NSString *)fileName {
    return self.messageModel.fileName;
}

- (NSString *)fileLocalPath {
    return self.messageModel.fileLocalPath;
}

- (NSString *)fileSize {
    return self.messageModel.fileSize;
}

- (NSString *)mediaDuration {
    return self.messageModel.mediaDuration;
}

- (NSString *)senderId {
    return self.messageModel.senderId;
}

- (NSString *)senderDisplayName {
    return self.messageModel.senderDisplayName;
}

- (NSDate *)date {
    return self.messageModel.date;
}

- (NSString *)text {
    return self.messageModel.text;
}

- (id<JSQMessageMediaData>)media {
    return self.mediaData;
}

- (BOOL)isMediaMessage {
    return self.mediaMessage;
}

#pragma mark - NSObject

- (BOOL)isEqual:(id)object {
    if (self == object) {
        return YES;
    }

    if (![object isKindOfClass:[self class]]) {
        return NO;
    }

    JSQMessage *aMessage = (JSQMessage *)object;

    if (self.isMediaMessage != aMessage.isMediaMessage) {
        return NO;
    }

    BOOL hasEqualContent = self.isMediaMessage ? [self.media isEqual:aMessage.media] : [self.text isEqualToString:aMessage.text];

    return [self.senderId isEqualToString:aMessage.senderId]
           && [self.senderDisplayName isEqualToString:aMessage.senderDisplayName]
           && ([self.date compare:aMessage.date] == NSOrderedSame)
           && hasEqualContent;
}

- (NSUInteger)hash {
    NSUInteger contentHash = self.isMediaMessage ? [self.media mediaHash] : self.text.hash;
    return self.senderId.hash ^ self.date.hash ^ contentHash;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, text=%@, media=%@>",
            [self class], [self senderId], [self senderDisplayName], [self date], @([self isMediaMessage]), [self text], [self media]];
}

- (id)debugQuickLookObject {
    return [self.media mediaView] ? : [self.media mediaPlaceholderView];
}

#pragma mark - NSCoding

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        _messageModel.senderId = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderId))];
        _messageModel.senderDisplayName = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderDisplayName))];
        _messageModel.date = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(date))];
        _messageModel.text = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(text))];
        _mediaData = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(media))];
        _mediaMessage = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isMediaMessage))];

        _messageModel.sessionID = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(sessionID))];
        _messageModel.messageID = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(messageID))];
        _messageModel.mimeType = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(mimeType))];
        _messageModel.messageType = [aDecoder decodeIntForKey:NSStringFromSelector(@selector(messageType))];
        _messageModel.messageStatus = [aDecoder decodeIntForKey:NSStringFromSelector(@selector(messageStatus))];

        _messageModel.fileName = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(fileName))];
        _messageModel.fileLocalPath = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(fileLocalPath))];
        _messageModel.fileSize = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(fileSize))];
        _messageModel.mediaDuration = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(mediaDuration))];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.messageModel.senderId forKey:NSStringFromSelector(@selector(senderId))];
    [aCoder encodeObject:self.messageModel.senderDisplayName forKey:NSStringFromSelector(@selector(senderDisplayName))];
    [aCoder encodeObject:self.messageModel.date forKey:NSStringFromSelector(@selector(date))];
    [aCoder encodeObject:self.messageModel.text forKey:NSStringFromSelector(@selector(text))];

    [aCoder encodeObject:self.messageModel.sessionID forKey:NSStringFromSelector(@selector(sessionID))];
    [aCoder encodeObject:self.messageModel.messageID forKey:NSStringFromSelector(@selector(messageID))];
    [aCoder encodeObject:self.messageModel.mimeType forKey:NSStringFromSelector(@selector(mimeType))];
    [aCoder encodeInt:(int)self.messageModel.messageType forKey:NSStringFromSelector(@selector(messageType))];
    [aCoder encodeInt:(int)self.messageModel.messageStatus forKey:NSStringFromSelector(@selector(messageStatus))];

    [aCoder encodeObject:self.messageModel.fileName forKey:NSStringFromSelector(@selector(fileName))];
    [aCoder encodeObject:self.messageModel.fileLocalPath forKey:NSStringFromSelector(@selector(fileLocalPath))];
    [aCoder encodeObject:self.messageModel.fileSize forKey:NSStringFromSelector(@selector(fileSize))];
    [aCoder encodeObject:self.messageModel.mediaDuration forKey:NSStringFromSelector(@selector(mediaDuration))];

    [aCoder encodeBool:self.mediaMessage forKey:NSStringFromSelector(@selector(isMediaMessage))];

    if ([self.mediaData conformsToProtocol:@protocol(NSCoding)]) {
        [aCoder encodeObject:self.mediaData forKey:NSStringFromSelector(@selector(media))];
    }
}

#pragma mark - NSCopying

- (instancetype)copyWithZone:(NSZone *)zone {
    JSQMessage *message = [[[self class] allocWithZone:zone] initWithMessageModel:self.messageModel withMessageMediaData:self.media];

    return message;
}

@end
